// DCMTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <time.h>
#include <assert.h>
#include <conio.h>
#include <process.h>
#include "..\DCMInterface.h"
#include "..\DataCacheManager.h"


#define TEST_CASE_WRITE_DATA     _TEXT("write")
#define TEST_CASE_READ_DATA      _TEXT("read")
#define TEST_CASE_READ_WRITE     _TEXT("wr")

int TestWrite();
int TestRead();
int TestReadWrite();

IDataCacheManager * CreateDCM()
{
	IDataCacheManager * pDCM = CreateDataCacheManager("Tester");
	assert(pDCM);
	pDCM->InitCacheMgr(0, ".\\TestCache");
	return pDCM;
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc != 2)
	{
		printf("Please provide test options.\n");
		return 0;
	}
	else
	{
		if (lstrcmp(argv[1], TEST_CASE_WRITE_DATA) == 0)
			return TestWrite();
		else if (lstrcmp(argv[1], TEST_CASE_READ_DATA) == 0)
			return TestRead();
		else if (lstrcmp(argv[1], TEST_CASE_READ_WRITE) == 0)
			return TestReadWrite();
	}
	return 0;
}

int TestWrite()
{
	IDataCacheManager *pDCM = CreateDCM();
	
	IDataCacheItem * pDCI = pDCM->CreateCacheItem(123456789, "TestWrite");
	eResult Res = RET_ERROR;
	assert (pDCI);
	unsigned char * buf = new unsigned char[1000];
	for (unsigned int i = 0; i < 1000; i++)
		buf[i] = i&0xff;
	bool index_table[1000];
	memset(index_table, 0, sizeof(bool)*1000);

	srand(time(NULL));
	for (int i = 0; i < 1000; i++)
	{
		int index = rand()*1000 / RAND_MAX;
		if (index >= 1000)
			index = 0;
		while (index_table[index])
		{
			index++;
			if (index == 1000)
				index = 0;
		}

		//printf("[%d]>>WriteData %u, length = %d\n", i, index*10000, 10000);
		pDCI->WriteData((char*)buf, index * 1000, 1000, false);
		//getch();
		index_table[index] = true;
	}

	//Dump the data.
	FILE * pFile = fopen("segmentdump.bin", "wb");
	char readbuf[32768];
	int count = 0;
	for (; count < 1000; count++)
	{
		unsigned int size = 32768;
		if (pDCI->ReadData(readbuf, count* 32768, size, &size, true, 0, 0) == RET_OK)
		{
			fwrite(readbuf, 1, 32768, pFile);	
		}
		else
			break;
	}
	fclose(pFile);
	printf("%d Segment have been saved.\n", count);
	pDCI->Release("TestWrite");
	DeleteDataCacheManager(pDCM, "Tester");

	// Check the result
	pFile = fopen("segmentdump.bin", "rb");
	char in[1000];
	for (int i = 0; i < 1000; i++)
	{
		int n = fread(in, 1, 1000, pFile);
		if (n == 1000)
		{
			for (unsigned int u = 0; u < 1000; u++)
				if (buf[u] != (u&0xff))
				{
					printf("Error on checking: on unit %d, offset %d\n", i, u);
					break;
				}
		}
		else
		{
			printf("Total %d unit is read.\n", i);
			break;
		}
	}
	fclose(pFile);
	getch();
	return 0;
}

int TestRead()
{
	IDataCacheManager *pDCM = CreateDCM();
	IDataCacheItem * pDCI = pDCM->CreateCacheItem(123456789, "TestRead");
	eResult Res = RET_ERROR;
	assert (pDCI);

	unsigned char rdbf[50000];
	for (int i = 0; i < 10; i++)
	{
		unsigned int ReadCount = 0;
		eResult Res = pDCI->ReadData((char*)rdbf, i * 50000, 50000, &ReadCount, true, 1000);
		if (Res == RET_OK)
		{
			/*
			for (unsigned int u = 0; u < 1000; u++)
			if (rdbf[u] != (u&0xff))
			{
				printf("Error on reading: on unit %d, offset %d\n", i, u);
				break;
			}
			*/
			printf("Successfully read data unit %d, read count = %u\n", i, ReadCount);
		}
		else
		{
			if (Res == RET_TIMEOUT)
				printf("Error on reading: Operation timeout on unit %d, only %d bytes read.\n", i, ReadCount);
			else
				printf("Error on reading: Error.\n");
		}
	}
	getch();
	pDCI->Release("TestRead");
	DeleteDataCacheManager(pDCM, "Tester");

	return 0;
}

static const unsigned int gTotalSize = 1024*1024*4 - 18679;

void Thread_Writer(void * param)
{
	IDataCacheItem * pDCI = (IDataCacheItem*)param;
	pDCI->SetTotalSize(gTotalSize);

	unsigned char * buf = new unsigned char[1000];
	for (unsigned int i = 0; i < 1000; i++)
		buf[i] = i&0xff;
	bool index_table[1000];
	memset(index_table, 0, sizeof(bool)*1000);

	srand(time(NULL));
	unsigned int WriteBytes = 0;
	unsigned int index = 0;
	while (WriteBytes < gTotalSize)
	{
#ifdef _RANDOM_WRITE
		index = rand()*1000 / RAND_MAX;
		if (index >= 1000)
			index = 0;
		while (index_table[index])
		{
			index++;
			if (index == 1000)
				index = 0;
		}
#else
#endif

		if (WriteBytes+1000 > gTotalSize)
		{
			printf("WriteData offset = %u, length = %d\n", WriteBytes, gTotalSize - WriteBytes);
			pDCI->WriteData((char*)buf,  WriteBytes, gTotalSize - WriteBytes, false);
			WriteBytes +=  gTotalSize - WriteBytes;
		}
		else
		{
			printf("WriteData offset = %u, length = %d\n", WriteBytes, 1000);
			pDCI->WriteData((char*)buf, WriteBytes, 1000, false);
			WriteBytes += 1000;
		}
		//getch();
		index_table[index] = true;
		Sleep(1);
	}
	pDCI->Release("Thread writer");
}

int TestReadWrite()
{
	IDataCacheManager *pDCM = CreateDCM();
	IDataCacheItem * pDCI = pDCM->CreateCacheItem(123456789, "TestRead");
	eResult Res = RET_ERROR;
	assert (pDCI);
	pDCI->AddRef("Thread writer");
	HANDLE hThread = (HANDLE)_beginthread(Thread_Writer, 0, pDCI);

	//Sleep(5000);

	unsigned char rdbf[2048];
	Res = RET_OK;
	unsigned int Offset = 0;
	while (Res == RET_OK)
	{
		unsigned int ReadCount = 0;
		Res = pDCI->ReadData((char*)rdbf, Offset, 2048, &ReadCount, true, INFINITE);
		if (Res == RET_OK || Res == RET_LASTSEG)
		{
			printf("Successfully read data TotalRead = %u, read bytes = %u\n", Offset + ReadCount, ReadCount);
		}
		else
		{
			if (Res == RET_TIMEOUT)
				printf("Error on reading: Operation timeout, only %d bytes read.\n", ReadCount);
			else
				printf("Error on reading: Error.\n");
			break;
		}
		Offset += ReadCount;
	}
	getch();
	//pDCI->Release("TestRead");
	WaitForSingleObject(hThread, 10000);

	DeleteDataCacheManager(pDCM, "Tester");

	return 0;
}
